package basic

import (
	"context"
	"io"
	"io/ioutil"

	"github.com/ipfs/go-ipfs-cmdkit/files"

	. "gitee.com/liukexing/isrn/api"
)

type AddCommand struct {
	Shell
}

type object struct {
	Hash string
}

// Add a file to ipfs from the given reader, returns the hash of the added file
func (s *AddCommand) Add(r io.Reader) (string, error) {
	return s.AddWithOpts(r, true, false)
}

// AddNoPin a file to ipfs from the given reader, returns the hash of the added file without pinning the file
func (s *AddCommand) AddNoPin(r io.Reader) (string, error) {
	return s.AddWithOpts(r, false, false)
}

func (s *AddCommand) AddWithOpts(r io.Reader, pin bool, rawLeaves bool) (string, error) {
	var rc io.ReadCloser
	if rclose, ok := r.(io.ReadCloser); ok {
		rc = rclose
	} else {
		rc = ioutil.NopCloser(r)
	}

	// handler expects an array of files
	fr := files.NewReaderFile("", "", rc, nil)
	slf := files.NewSliceFile("", "", []files.File{fr})
	fileReader := files.NewMultiFileReader(slf, true)

	var out object
	return out.Hash, s.Request("add").
		Option("progress", false).
		Option("pin", pin).
		Option("raw-leaves", rawLeaves).
		Body(fileReader).
		Exec(context.Background(), &out)
}

/*
USAGE
  ipfs add <path>... - Add a file or directory to ipfs.

SYNOPSIS
  ipfs add [--recursive | -r] [--quiet | -q] [--quieter | -Q] [--silent] [--progress | -p] [--trickle | -t] [--only-hash | -n] [--wrap-with-directory | -w] [--hidden | -H] [--chunker=<chunker> | -s] [--pin=false] [--raw-leaves] [--nocopy] [--fscache] [--cid-version=<cid-version>] [--hash=<hash>] [--] <path>...

ARGUMENTS

  <path>... - The path to a file to be added to ipfs.

OPTIONS

  -r,          --recursive           bool   - Add directory paths recursively. Default: false.
  -q,          --quiet               bool   - Write minimal output.
  -Q,          --quieter             bool   - Write only final hash.
  --silent                           bool   - Write no output.
  -p,          --progress            bool   - Stream progress data.
  -t,          --trickle             bool   - Use trickle-dag format for dag generation.
  -n,          --only-hash           bool   - Only chunk and hash - do not write to disk.
  -w,          --wrap-with-directory bool   - Wrap files with a directory object.
  -H,          --hidden              bool   - Include files that are hidden. Only takes effect on recursive add.
  -s,          --chunker             string - Chunking algorithm, size-[bytes] or rabin-[min]-[avg]-[max]. Default: size-262144.
  --pin                              bool   - Pin this object when adding. Default: true.
  --raw-leaves                       bool   - Use raw blocks for leaf nodes. (experimental).
  --nocopy                           bool   - Add the file using filestore. (experimental).
  --fscache                          bool   - Check the filestore for pre-existing blocks. (experimental).
  --cid-version                      int    - Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental). Default: 0.
  --hash                             string - Hash function to use. Will set Cid version to 1 if used. (experimental). Default: sha2-256.

DESCRIPTION

  Adds contents of <path> to ipfs. Use -r to add directories.
  Note that directories are added recursively, to form the ipfs
  MerkleDAG.

  The wrap option, '-w', wraps the file (or files, if using the
  recursive option) in a directory. This directory contains only
  the files which have been added, and means that the file retains
  its filename. For example:

    > ipfs add example.jpg
    added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg
    > ipfs add example.jpg -w
    added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg
    added QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx

  You can now refer to the added file in a gateway, like so:

    /ipfs/QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx/example.jpg

  The chunker option, '-s', specifies the chunking strategy that dictates
  how to break files into blocks. Blocks with same content can
  be deduplicated. The default is a fixed block size of
  256 * 1024 bytes, 'size-262144'. Alternatively, you can use the
  rabin chunker for content defined chunking by specifying
  rabin-[min]-[avg]-[max] (where min/avg/max refer to the resulting
  chunk sizes). Using other chunking strategies will produce
  different hashes for the same file.

    > ipfs add --chunker=size-2048 ipfs-logo.svg
    added QmafrLBfzRLV4XSH1XcaMMeaXEUhDJjmtDfsYU95TrWG87 ipfs-logo.svg
    > ipfs add --chunker=rabin-512-1024-2048 ipfs-logo.svg
    added Qmf1hDN65tR55Ubh2RN1FPxr69xq3giVBz1KApsresY8Gn ipfs-logo.svg

  You can now check what blocks have been created by:

    > ipfs object links QmafrLBfzRLV4XSH1XcaMMeaXEUhDJjmtDfsYU95TrWG87
    QmY6yj1GsermExDXoosVE3aSPxdMNYr6aKuw3nA8LoWPRS 2059
    Qmf7ZQeSxq2fJVJbCmgTrLLVN9tDR9Wy5k75DxQKuz5Gyt 1195
    > ipfs object links Qmf1hDN65tR55Ubh2RN1FPxr69xq3giVBz1KApsresY8Gn
    QmY6yj1GsermExDXoosVE3aSPxdMNYr6aKuw3nA8LoWPRS 2059
    QmerURi9k4XzKCaaPbsK6BL5pMEjF7PGphjDvkkjDtsVf3 868
    QmQB28iwSriSUSMqG2nXDTLtdPHgWb4rebBrU7Q1j4vxPv 338
*/
